import cn.hutool.core.date.StopWatch;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.exception.MathArithmeticException;
import org.junit.jupiter.api.Test;

import java.util.concurrent.*;

/**
 * @Description TODO
 * @Author JFeng
 * @Date 2023/12/16
 */

@Slf4j
public class test {

    /**
     * 异常往大了抛可以，不能往小了抛
     * MathArithmeticException  extends  ArithmeticException  extends  Exception
     * 不能抛MathArithmeticException
     */
    @Test
    void testThrowException() {
        try {
            int a = 1 / 0;
        } catch (ArithmeticException e) {
            log.info(String.valueOf(e));
        }
        System.out.println("1");

    }

    @Test
    public void test() {
        System.out.println("1");
        System.out.println("1");
        System.out.println("2");
        System.out.println(Thread.currentThread().getName());
        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().isDaemon());
            while (true) {

            }
        });
        thread.setDaemon(true);
        thread.start();
    }


    /**
     * new Thread() 接收的是Runnable 接口的实现类，
     * FutureTask extends RunnableFuture extends Runnable，Future
     * Runnable 接口是再操作系统层面创建了一个线程，
     * Future   接口是定义了一些线程启动、停止、获取返回值的方法
     * new FutureTask()  接收的是Callable的实现类，所以能获取到返回值
     */
    @Test
    void test01() throws ExecutionException, InterruptedException {

        FutureTask<String> futureTask = new FutureTask<>(
                () -> {
                    System.out.println("arrive in Callable interface");
                    String name = Thread.currentThread().getName();
                    System.out.println("Callable thread name = " + name);
                    return name;
                }

        );

        Thread thread = new Thread(futureTask);
        thread.start();
        String res = futureTask.get();
        System.out.println("Callable Thread`result = " + res);
    }


    /**
     * FutureTask的缺点： 再调用get方法获取返回值的时候
     * 如果FutureTask还没有执行完，会导致主线程阻塞，等待get的结果。
     * public V get(long timeout, TimeUnit unit) 只等待固定时间
     * FutureTask 对结果的获取很不友好，破玩楞不用。
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    @Test
    void test02() throws InterruptedException, ExecutionException, TimeoutException {
        StopWatch watch = new StopWatch();
        watch.start();
        FutureTask<String> futureTask1 = new FutureTask<>(() -> {
//            log.info("This futureTask1 ID is {}", Thread.currentThread().threadId());
            int count = 0;
            for (int i = 0; i < 10; i++) {
                String res = HttpUtil.get("www.baidu.com");
//                log.info("Thread res-{} = {}", i, res);
                count += res.getBytes().length;
            }
            return String.valueOf(count);
        });
        FutureTask<String> futureTask2 = new FutureTask<>(() -> {
//            log.info("This futureTask2 ID is {}", Thread.currentThread().threadId());
            int count = 0;
            for (int i = 0; i < 10; i++) {
                String res = HttpUtil.get("www.baidu.com");
//                log.info("Thread res-{} = {}", i, res);
                count += res.getBytes().length;
            }
            return String.valueOf(count);
        });
        FutureTask<String> futureTask3 = new FutureTask<>(() -> {
//            log.info("This futureTask3 ID is {}", Thread.currentThread().threadId());
            int count = 0;
            for (int i = 0; i < 10; i++) {
                String res = HttpUtil.get("www.baidu.com");
//                log.info("Thread res-{} = {}", i, res);
                count += res.getBytes().length;
            }
            return String.valueOf(count);
        });
//        TimeUnit.SECONDS.sleep(2);
//        for (int i = 0; i < 20; i++) {
//            String res = HttpUtil.get("www.baidu.com");
//            log.info("res-{} = {}", i, res);
//        }
//        Thread thread = new Thread(futureTask);
//        thread.start();
//        System.out.println("sssssssssssssss==="+futureTask.get());
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.submit(futureTask1);
        executorService.submit(futureTask2);
        executorService.submit(futureTask3);
//        log.info("futureTask1 result = {}",futureTask1.get());
        try {
            log.info("futureTask1 result = {}", futureTask1.get(200, TimeUnit.MILLISECONDS));
        } catch (TimeoutException e) {
            log.info(e.toString());
        }

        watch.stop();
        log.info("耗时: {}", watch.getTotalTimeMillis());
        executorService.shutdown();
    }


    @Test
    void test03() throws ExecutionException, InterruptedException {
        System.out.println("This thread name`s " + Thread.currentThread().getName());
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
                    try {
                        System.out.println("This thread name`s " + Thread.currentThread().getName());
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    return "adc";
                }, executorService)
                .thenApply(f -> {
                    log.info("thenApply was executed, and this value is {}", f);
                    f += " thenApply executed.";
//                    int a = 1 / 0;
                    return f;
                })
                .handle((f, e) -> {
                    int a = 1 / 0;
                    return f + " handle was executed.";
                })
                .handle((f, e) -> {
                    return f + " thenApply was executed too.";
                })
                .whenComplete((v, e) -> {
                    if (e == null) {
                        log.info("this result is {}.", v);
                    }
                })
                .exceptionally(e -> {
                    e.printStackTrace();
                    log.info("this exception message is {}", e.getMessage());
                    return null;
                });
        TimeUnit.SECONDS.sleep(6);
        System.out.println(stringCompletableFuture.complete("This is default value."));
        System.out.println(stringCompletableFuture.get());
        executorService.shutdown();
    }


    @Test
    void test04() throws Exception {

        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            return "aa";
        }, threadPool).thenRunAsync(() -> {
//            try {
//                TimeUnit.SECONDS.sleep(3);
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
            System.out.println(Thread.currentThread().getName());
        }, threadPool).thenRun(() -> {
            System.out.println(Thread.currentThread().getName());
        });
        TimeUnit.SECONDS.sleep(5);
    }

    @Test
    void test05() throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(3);
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            return "aaa";
        }, pool);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            return "bbb";
        }, pool);

        CompletableFuture<String> res = future1.thenCombine(future2, (x, y) -> {
            System.out.println(Thread.currentThread().getName());
            return x + y;
        });
        System.out.println(res.join());

        TimeUnit.SECONDS.sleep(5);
        pool.shutdown();
        StopWatch watch = new StopWatch();
        watch.start();
        TimeUnit.SECONDS.sleep(1);
        watch.stop();
        System.out.println(watch.getTotalTimeMillis());
        watch.start();
        TimeUnit.SECONDS.sleep(2);
        watch.stop();
        System.out.println(watch.getTotalTimeMillis());

    }

    @Test
    void test06() throws InterruptedException {
        Phone phone = new Phone();
        ExecutorService pool = Executors.newFixedThreadPool(3);
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                return phone.sendEmail();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }, pool);
//        TimeUnit.SECONDS.sleep(2);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
//            return phone.sendSMS();
            return phone.hello();
        }, pool);
        System.out.println("future1.join() " + future1.join());
        System.out.println("future2.join() " + future2.join());
        pool.shutdown();
    }

    @Test
    void test07() throws InterruptedException {
        ExecutorService pool = Executors.newWorkStealingPool();
        Thread t1 = new Thread(() -> {
            int cout = 0;
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("true");
                    break;
                }
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
                    Thread.currentThread().interrupt(); // 没有这行这个线程将一直执行
                }
                System.out.println(++cout);
            }
        }, "t1");
        t1.start();
        TimeUnit.SECONDS.sleep(3);
        t1.interrupt();
        System.out.println("      t1.IsInterrupt()=" + t1.isInterrupted());
        TimeUnit.SECONDS.sleep(5);
        pool.shutdown();
        System.out.println("====================");
        System.out.println("main`s interrupted = " + Thread.currentThread().isInterrupted());
        Thread.currentThread().interrupt();
        System.out.println("main`s interrupted = " + Thread.currentThread().isInterrupted());
        System.out.println("Thread.interrupted() = " + Thread.interrupted());
        System.out.println("main`s interrupted = " + Thread.currentThread().isInterrupted());

    }
}

class Phone {
    public synchronized String sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail ...");
        return "sendEmail ok";
    }

    public String sendSMS() {
        synchronized (this) {
            System.out.println("sendSMS ...");
            return "sendSMS ok";
        }
    }

    public String hello() {
        System.out.println("hello .");
        return "hello ok";
    }

    public String hello1() {
        System.out.println("hello ...");
        return "hello ok";
    }
}